
#include "spi_defines.h"
#include "gkt_malloc.h"
#include "gkt_driver.h"
#include "gkt_spi.h"
#include "g_hspi.h"

/************************************************************
 * sck, mosi, miso pads
 ************************************************************/
static const gkt_gpio_padmux_desc_s sc_spi_padmux_descs[SPI_DEVICE_MAX][SPI_PAD_MAX] = {
#if (SPI0_SLAVE_NUMS > 0)
	[SPI_DEVICE_SPI0] = {	/* spi0 */
		[SPI_PAD_SCK] = GKT_GPIO_PADMUX_DESC_DEFINE(GKT_CONFIG_SPI0_SCK_PAD, SPID0_SCK),
		[SPI_PAD_MOSI] = GKT_GPIO_PADMUX_DESC_DEFINE(GKT_CONFIG_SPI0_MOSI_PAD, SPID0_MOSI),
		[SPI_PAD_MISO] = GKT_GPIO_PADMUX_DESC_DEFINE(GKT_CONFIG_SPI0_MISO_PAD, SPID0_MISO),		
	},
#endif
#if (SPI1_SLAVE_NUMS > 0)
	[SPI_DEVICE_SPI1] = {	/* spi1 */
		[SPI_PAD_SCK] = GKT_GPIO_PADMUX_DESC_DEFINE(GKT_CONFIG_SPI1_SCK_PAD, SPID1_SCK),
		[SPI_PAD_MOSI] = GKT_GPIO_PADMUX_DESC_DEFINE(GKT_CONFIG_SPI1_MOSI_PAD, SPID1_MOSI),
		[SPI_PAD_MISO] = GKT_GPIO_PADMUX_DESC_DEFINE(GKT_CONFIG_SPI1_MISO_PAD, SPID1_MISO),
	},
#endif
#if (SPI2_SLAVE_NUMS > 0)
	[SPI_DEVICE_SPI2] = {	/* hspi */
		[SPI_PAD_SCK] = GKT_GPIO_PADMUX_DESC_DEFINE(GKT_CONFIG_SPI2_SCK_PAD, HSPI_SCK),
		[SPI_PAD_MOSI] = GKT_GPIO_PADMUX_DESC_DEFINE(GKT_CONFIG_SPI2_MOSI_PAD, HSPI_MOSI),
		[SPI_PAD_MISO] = GKT_GPIO_PADMUX_DESC_DEFINE(GKT_CONFIG_SPI2_MISO_PAD, HSPI_MISO),
	},
#endif
};


/************************************************************
 * slave ncs pads
 ************************************************************/
static const uint8_t sc_spi_slaves_ncs_pads[SPI_SLAVE_TOTAL_NUMS] = {
#if (SPI0_SLAVE_NUMS > 0)
	SPI_SLAVES_NCS_PADS_DEFINE(SPI_DEVICE_SPI0),
#endif
#if (SPI1_SLAVE_NUMS > 0)
	SPI_SLAVES_NCS_PADS_DEFINE(SPI_DEVICE_SPI1),
#endif
#if (SPI2_SLAVE_NUMS > 0)
	SPI_SLAVES_NCS_PADS_DEFINE(SPI_DEVICE_SPI2)
#endif
};


/************************************************************
 * spi device attr
 ************************************************************/
static const spi_attr_s sc_spi_attrs[SPI_DEVICE_MAX] = {
	[SPI_DEVICE_SPI0] = {
		.device	= (void *)MSPI0, 
		.irq_no	= GKT_SPI0_IRQ_NO, 
		.slave_nums	= SPI0_SLAVE_NUMS, 
		.slave_base_offset	= 0, 
		.ncs_func	= SPID0_NCS,
	},
	[SPI_DEVICE_SPI1] = { 
		.device	= (void *)MSPI1,
		.irq_no	= GKT_SPI1_IRQ_NO, 
		.slave_nums	= SPI1_SLAVE_NUMS, 
		.slave_base_offset	= SPI0_SLAVE_NUMS, 
		.ncs_func	= SPID1_NCS,
	},
	[SPI_DEVICE_SPI2] = {
		.device	= (void *)MHSPI, 
		.irq_no	= GKT_SPI2_IRQ_NO, 
		.slave_nums	= SPI2_SLAVE_NUMS, 
		.slave_base_offset	= SPI0_SLAVE_NUMS + SPI1_SLAVE_NUMS, 
		.ncs_func	= HSPI_NCS,
	},
};

static spi_s s_spi;

static int spi_handle_is_valid(gkt_handle_t handle)
{
	uint32_t dev_id, slave_id;

	if ((handle & SPI_MAGIC_MASK) == SPI_MAGIC) {
		dev_id = SPI_DEV_ID(handle);
		if (dev_id < SPI_DEVICE_MAX) {
			slave_id = SPI_SLAVE_ID(handle);
			if (slave_id < sc_spi_attrs[dev_id].slave_nums)
				return 1;
		}
	}

	return 0;
}

void gkt_hspi_irq_handler(void)
{
	spi_device_s *device;
	uint32_t irq_no;

	irq_no = gkt_irq_get_current();
	if (sc_spi_attrs[SPI_DEVICE_HSPI].irq_no == irq_no) {
		device = &s_spi.devices[SPI_DEVICE_HSPI];
		// TODO: 
		/* disable & clear interrupt status */
		gkt_irq_disable(irq_no);
		gkt_irq_clear_pending(irq_no);
		
		/* notify blocked thread */
		if ((device->active_slave_id < sc_spi_attrs[SPI_DEVICE_HSPI].slave_nums)
			&& device->blocked)
		{
			if (device->semaphore) {
				gkt_semaphore_release(device->semaphore);
			}
		}
	}
	
}
#if (SPI0_SLAVE_NUMS + SPI1_SLAVE_NUMS) > 0
void gkt_spi_irq_handler(void)
{
	spi_device_s *device;
	uint32_t dev_id, irq_no;

	irq_no = gkt_irq_get_current();
	for (dev_id = 0; dev_id < SPI_DEVICE_MAX; dev_id++) {
		if (sc_spi_attrs[dev_id].irq_no == irq_no) {
			device = &s_spi.devices[dev_id];

			if (dev_id < SPI_DEVICE_HSPI) {
				/* disable & clear interrupt status */
				G_SPI_ITConfig((SPI_TypeDef *)sc_spi_attrs[dev_id].device, DISABLE);
				G_SPI_ClearITPendingBit((SPI_TypeDef *)sc_spi_attrs[dev_id].device);

				/* notify blocked thread */
				if ((device->active_slave_id < sc_spi_attrs[dev_id].slave_nums)
					&& device->blocked)
				{
					gkt_semaphore_release(device->semaphore);
				}
			}
			break;
		}
	}
}
#endif

int gkt_spi_init(void)
{
	spi_device_s *device;
	uint32_t dev_id;

	s_spi.mutex = gkt_mutex_create(0);
	if (!s_spi.mutex)
		return GKT_ECREATE;

	for (dev_id = 0; dev_id < SPI_DEVICE_MAX; dev_id++) {
		device = &s_spi.devices[dev_id];
		device->c_attr = &sc_spi_attrs[dev_id];
		device->active_slave_id = ~0;

		if (sc_spi_attrs[dev_id].slave_nums > 0) {
			device->c_slaves_ncs_pads = &sc_spi_slaves_ncs_pads[device->c_attr->slave_base_offset];
			device->slaves = &s_spi.slaves[device->c_attr->slave_base_offset];

			device->semaphore = gkt_semaphore_create(1, 0);
			if (!device->semaphore)
				return GKT_ECREATE;

			gkt_irq_set_priority(device->c_attr->irq_no, GKT_IRQ_PRIORITY_NORMAL);
			gkt_irq_enable(device->c_attr->irq_no);
		}
	}

	s_spi.init_ok = 1;

	return GKT_SUCCESS;
}

gkt_handle_t gkt_spi_open(int master,
				uint32_t dev_id, uint32_t slave_id)
{
	gkt_handle_t handle = GKT_HANDLE_INVALID;
	spi_slave_s *slave;

	GKT_ASSERT(master != 0);

	if (s_spi.init_ok
		&& (dev_id < SPI_DEVICE_MAX)
		&& (slave_id < sc_spi_attrs[dev_id].slave_nums))
	{
		slave = &s_spi.devices[dev_id].slaves[slave_id];
		if (slave->state < SPI_SLAVE_ST_OPENED)
			slave->state = SPI_SLAVE_ST_OPENED;
		handle = SPI_HANDLE(dev_id, slave_id);
	}

	return handle;
}

int gkt_spi_config(gkt_handle_t handle, 
			gkt_spi_config_params_s *params)
{
	spi_device_s *device;
	spi_slave_s *slave;
	uint32_t dev_id, slave_id;
	int retval = GKT_EPARAM;

	if (spi_handle_is_valid(handle) 
		&& params && (params->clock_mode < GKT_SPI_CLOCK_MODE_MAX)
		&& (params->max_frequence > 0)
		&& ((8 == params->data_width) || (16 == params->data_width)))
	{
		dev_id = SPI_DEV_ID(handle);
		device = &s_spi.devices[dev_id];
		slave_id = SPI_SLAVE_ID(handle);
		slave = &device->slaves[slave_id];

		if (slave->state < SPI_SLAVE_ST_OPENED)
			return GKT_ENOTOPEN;
		else if (slave->state >= SPI_SLAVE_ST_START)
			return GKT_EPERMIT;

		slave->clock_mode = (uint8_t)params->clock_mode;
		slave->data_bytes = (uint8_t)(params->data_width >> 3);
		slave->max_frequence = params->max_frequence;
		slave->flags = params->flags;

#if (SPI2_SLAVE_NUMS > 0)
		if (SPI_DEVICE_HSPI == dev_id) {
			/*hspi clk init*/
			if (!device->hspi_clk_configed) {
				G_SYSCTRL_AHBPeriphClockCmd(SYSCTRL_AHBPeriph_HSPI,ENABLE);
				G_SYSCTRL_PER2HspiClkCtrl(RC_192M,PER2_RC192M,SYSCTRL_CLK_Div12);//SYSCTRL_CLK_Div2
				device->hspi_clk_configed = 1;
			}
		}
#endif
		/* config padmux */
		if (!device->pad_sck_configed) {
			gkt_gpio_padmux_config(&sc_spi_padmux_descs[dev_id][SPI_PAD_SCK]);
			device->pad_sck_configed = 1;
		}
		if (!(slave->flags & GKT_SPI_CF_TXD_NC) && !device->pad_mosi_configed) {
			gkt_gpio_padmux_config(&sc_spi_padmux_descs[dev_id][SPI_PAD_MOSI]);
			device->pad_mosi_configed = 1;
		}
		if (!(slave->flags & GKT_SPI_CF_RXD_NC) && !device->pad_miso_configed) {
			gkt_gpio_padmux_config(&sc_spi_padmux_descs[dev_id][SPI_PAD_MISO]);
			device->pad_miso_configed = 1;
		}

		slave->state = SPI_SLAVE_ST_CONFIGD;

		retval = GKT_SUCCESS;
	}

	return retval;
}

int gkt_spi_set_data_width(gkt_handle_t handle, 
				uint32_t data_width)
{
	spi_slave_s *slave;
	int retval;

	if (spi_handle_is_valid(handle)
		&& ((8 == data_width) || (16 == data_width))) 
	{
		slave = &s_spi.devices[SPI_DEV_ID(handle)].slaves[SPI_SLAVE_ID(handle)];
		slave->data_bytes = data_width >> 3;
		retval = GKT_SUCCESS;
	}
	else
		retval = GKT_EPARAM;

	return retval;
}

static int spi_master_assemble_datas(
			spi_device_s *device, spi_slave_s *slave,
			const void *cmd, uint32_t cmd_size,
			const void *data, uint32_t data_size)
{
	uint32_t total_size;

	//GKT_ASSERT(1 == slave->data_bytes);

	total_size = cmd_size + data_size;
	if (!device->tmp_buffer
		|| (total_size > device->tmp_buffer_size)) 
	{
		if (device->tmp_buffer) {
			gkt_free(device->tmp_buffer);
			device->tmp_buffer = NULL;
			device->tmp_buffer_size = 0;
		}

		total_size = (total_size + 0x07) & (~0x7);
		device->tmp_buffer = (uint8_t *)gkt_malloc(total_size);
		if (device->tmp_buffer)
			device->tmp_buffer_size = total_size;
		else
			return GKT_ENOMEMORY;
	}

	memcpy(device->tmp_buffer, cmd, cmd_size);
	memcpy(device->tmp_buffer + cmd_size, data, data_size);

	return GKT_SUCCESS;
}

static int spi_master_active_slave(spi_device_s *device,
				uint32_t slave_id)
{
	int retval;

	gkt_mutex_lock(s_spi.mutex, GKT_INFINITE);
	if (device->active_slave_id >= device->c_attr->slave_nums) {
		device->active_slave_id = slave_id;
		retval = GKT_SUCCESS;
	}
	else
		retval = GKT_EBUSY;
	gkt_mutex_unlock(s_spi.mutex);

	return retval;
}

static void spi_master_reset_blocked(spi_device_s *device, 
				uint32_t timeout)
{
	if (timeout > 0) {
		gkt_semaphore_acquire(device->semaphore, 0);
		device->blocked = 1;
	}
	else
		device->blocked = 0;
}

static void spi_master_terminate(spi_device_s *device)
{
	device->blocked = 0;
	device->active_slave_id = ~0;
}

static void spi_master_config_ncs(spi_device_s *device, 
				spi_slave_s *slave, uint32_t slave_id)
{
	gkt_gpio_padmux_desc_s padmux_desc;

	if (!(slave->flags & GKT_SPI_CF_CSN_SOFT)) {
		padmux_desc.pin = device->c_slaves_ncs_pads[slave_id];
		padmux_desc.func = device->c_attr->ncs_func;
		gkt_gpio_padmux_config(&padmux_desc);
	}
}

#if ((SPI0_SLAVE_NUMS + SPI1_SLAVE_NUMS) > 0)
/*
 *   MODE0: CPOL = 0, CPHA = 0
 *   MODE1: CPOL = 0, CPHA = 1
 *   MODE2: CPOL = 1, CPHA = 0
 *   MODE3: CPOL = 1, CPHA = 1
 */ 
static const uint8_t sc_spi_clock_mode_cpols[GKT_SPI_CLOCK_MODE_MAX] = {
	SPI_CPOL_Low, SPI_CPOL_Low, 
	SPI_CPOL_High, SPI_CPOL_High
};
static const uint8_t sc_spi_clock_mode_cphas[GKT_SPI_CLOCK_MODE_MAX] = {
	SPI_CPHA_First_Edge, SPI_CPHA_Second_Edge, 
	SPI_CPHA_First_Edge, SPI_CPHA_Second_Edge
};

static void spi_master_init_hw(spi_device_s *device, 
			spi_slave_s *slave)
{
	G_SPI_InitTypeDef SPI_InitStruct;
	uint32_t RW_Delay;

	SPI_InitStruct.Mode = SPI_Mode_Master;
	SPI_InitStruct.BaudRatePrescaler = SPI_BaudRatePrescaler_4;	// TODO:
	SPI_InitStruct.CPOL = sc_spi_clock_mode_cpols[slave->clock_mode];
	SPI_InitStruct.CPHA = sc_spi_clock_mode_cphas[slave->clock_mode];
	SPI_InitStruct.DCMIMODE = (1 == slave->data_bytes) ? SPI_DCMIMODE_8 : SPI_DCMIMODE_16;

	RW_Delay = slave->flags & GKT_SPI_CF_RW_DELAY_CLKS_MASK;
	if ((RW_Delay > 0) && (RW_Delay < 127))
		SPI_InitStruct.RW_Delay = RW_Delay;
	else if (!RW_Delay)
		SPI_InitStruct.RW_Delay = 1;
	else
		SPI_InitStruct.RW_Delay = 126;

	SPI_InitStruct.Slv_Bidir_En = SPI_SLV_BIDIR_DISABLE;
	SPI_InitStruct.RX_Phase_Sel = (slave->flags & GKT_SPI_CF_RX_SAMPLE_DELAY_1CLK) ? SPI_RX_PHASE_SEL_DELAY : SPI_RX_PAHSE_SEL_NORMAL;
	SPI_InitStruct.FirstBit_Sel = (slave->flags & GKT_SPI_CF_LSB) ? SPI_FIRSTBIT_LSB : SPI_FIRSTBIT_MSB;
	SPI_InitStruct.Wait_Dma = SPI_WAIT_DMA_ENABLE;
	G_SPI_Init((SPI_TypeDef *)device->c_attr->device, &SPI_InitStruct);

	G_SPI_ClearITPendingBit((SPI_TypeDef *)device->c_attr->device);
	G_SPI_ITConfig((SPI_TypeDef *)device->c_attr->device, ENABLE);
}
#endif

#if (SPI2_SLAVE_NUMS > 0)
static const uint8_t sc_hspi_clock_mode_cpols[GKT_SPI_CLOCK_MODE_MAX] = {
	HSPI_CPOL_Low, HSPI_CPOL_Low, 
	HSPI_CPOL_High, HSPI_CPOL_High
};
static const uint8_t sc_hspi_clock_mode_cphas[GKT_SPI_CLOCK_MODE_MAX] = {
	HSPI_CPHA_First_Edge, HSPI_CPHA_Second_Edge, 
	HSPI_CPHA_First_Edge, HSPI_CPHA_Second_Edge
};

static int hspi_master_init_hw(spi_device_s *device, 
								spi_slave_s *slave)
{
	G_HSPI_InitTypeDef HSPI_InitStruct;

	G_HSPI_DeInit();
	HSPI_InitStruct.SlaveMode = HSPI_Mode_Host;
	HSPI_InitStruct.RxAdjClk = HSPI_CTRL_RXADJCLK_0;
	HSPI_InitStruct.ClkDiv = HSPI_CTRL_CLKDIV_DIV0;
	HSPI_InitStruct.TxRxDly = HSPI_CTRL_TXRXDLY_0;
	switch (slave->slave_id) 
	{
		case 0:
			HSPI_InitStruct.NcsDly = HSPI_CTRL_NCSDLY_0;
			break;
		case 1:
			HSPI_InitStruct.NcsDly = HSPI_CTRL_NCSDLY_1;
			break;
		case 2:
			HSPI_InitStruct.NcsDly = HSPI_CTRL_NCSDLY_2;
			break;
		case 3:
			HSPI_InitStruct.NcsDly = HSPI_CTRL_NCSDLY_3;
			break;
		case 4:
			HSPI_InitStruct.NcsDly = HSPI_CTRL_NCSDLY_4;
			break;
		case 5:
			HSPI_InitStruct.NcsDly = HSPI_CTRL_NCSDLY_5;
			break;
		case 6:
			HSPI_InitStruct.NcsDly = HSPI_CTRL_NCSDLY_6;
			break;	
		case 7:
			HSPI_InitStruct.NcsDly = HSPI_CTRL_NCSDLY_7;
			break;
		default:
			HSPI_InitStruct.NcsDly = HSPI_CTRL_NCSDLY_0;
			break;
	}	
	HSPI_InitStruct.TxRxSeq = HSPI_TxRx_Sequence_Tx_First;
	HSPI_InitStruct.CPHA = sc_hspi_clock_mode_cphas[slave->clock_mode];
	HSPI_InitStruct.CPOL = sc_hspi_clock_mode_cpols[slave->clock_mode];
	HSPI_InitStruct.SpiHwStartSel = HSPI_Hw_Start_Sel_DMA0;
	G_HSPI_Init(&HSPI_InitStruct);
	
	gkt_irq_enable(device->c_attr->irq_no);
	G_HSPI_ITConfig(DMA_Done_IRQ, ENABLE);

	G_HSPI_PingpangEnableCmd(DISABLE);
	G_HSPI_DmaAutoStartCmd(ENABLE);
	G_HSPI_DmaEnableCmd(ENABLE);
	G_HSPI_HwStartCmd(DISABLE);
	G_HSPI_EnableCmd(ENABLE);

	return GKT_SUCCESS;
}
#endif

int gkt_spi_master_write(gkt_handle_t handle,
			const void *cmd, uint32_t cmd_size,
			const void *data, uint32_t data_size, 
			uint32_t timeout)
{
	spi_device_s *device;
	spi_slave_s *slave;
	uint32_t dev_id, slave_id;
	const uint8_t *c_send_buff;
	uint32_t send_size;
	int retval=GKT_SUCCESS;

	if (spi_handle_is_valid(handle)
		&& ((cmd && (cmd_size > 0)) || (data && (data_size > 0)))) 
	{
		dev_id = SPI_DEV_ID(handle);
		device = &s_spi.devices[dev_id];
		slave_id = SPI_SLAVE_ID(handle);
		slave = &device->slaves[slave_id];

		retval = spi_master_active_slave(device, slave_id);
		if (retval != GKT_SUCCESS)
			return retval;

		spi_master_reset_blocked(device, timeout);

#if (SPI0_SLAVE_NUMS + SPI1_SLAVE_NUMS) > 0
		if (dev_id < SPI_DEVICE_HSPI) {
			spi_master_config_ncs(device, slave, slave_id);
			spi_master_init_hw(device, slave);

			if (cmd && data) {
				retval = spi_master_assemble_datas(device, slave,
							cmd, cmd_size, data, data_size);
				if (retval != GKT_SUCCESS) {
					spi_master_terminate(device);
					return retval;
				}

				c_send_buff = (const uint8_t *)device->tmp_buffer;
				send_size = cmd_size + data_size;
			}
			else if (cmd) {
				c_send_buff = cmd;
				send_size = cmd_size;
			}
			else {
				c_send_buff = data;
				send_size = data_size;
			}
			G_SPI_SendBuff((SPI_TypeDef *)device->c_attr->device, 
					c_send_buff, send_size);
		}
#endif
#if (SPI2_SLAVE_NUMS > 0)
		if (SPI_DEVICE_HSPI == dev_id) {
			// TODO: 		
			spi_master_config_ncs(device, slave, slave_id);
			hspi_master_init_hw(device, slave);		
			if (cmd && data) {
				retval = spi_master_assemble_datas(device, slave,
							cmd, cmd_size, data, data_size);
				if (retval != GKT_SUCCESS) {
					spi_master_terminate(device);
					return retval;
				}

				c_send_buff = (const uint8_t *)device->tmp_buffer;
				send_size = cmd_size + data_size;
			}
			else if (cmd) {
				c_send_buff = cmd;
				send_size = cmd_size;
			}
			else {
				c_send_buff = data;
				send_size = data_size;
			}

			if (send_size == 1)
				G_HSPI_SendData((uint8_t)*c_send_buff);
			else
				G_HSPI_SendBuff((uint8_t *)c_send_buff, send_size);
		}
#endif

		if (timeout > 0)
			retval = gkt_semaphore_acquire(device->semaphore, timeout);
		spi_master_terminate(device);
	}
	else
		retval = GKT_EPARAM;

	return retval;
}

int gkt_spi_master_read(gkt_handle_t handle,
			const uint8_t *cmd, uint32_t cmd_size,
			void *read_buff, uint32_t read_size,
			uint32_t timeout)
{
	spi_device_s *device;
	spi_slave_s *slave;
	uint32_t dev_id, slave_id;
	int retval;

	if (spi_handle_is_valid(handle)
		&& read_buff && (read_size > 0)) 
	{
		dev_id = SPI_DEV_ID(handle);
		device = &s_spi.devices[dev_id];
		slave_id = SPI_SLAVE_ID(handle);
		slave = &device->slaves[slave_id];

		retval = spi_master_active_slave(device, slave_id);
		if (retval != GKT_SUCCESS)
			return retval;

		spi_master_reset_blocked(device, timeout);

#if (SPI0_SLAVE_NUMS + SPI1_SLAVE_NUMS) > 0
		if (dev_id < SPI_DEVICE_HSPI) {
			spi_master_config_ncs(device, slave, slave_id);
			spi_master_init_hw(device, slave);

			if (cmd && (cmd_size > 0)) {
				G_SPI_SendAndReceiveData((SPI_TypeDef *)device->c_attr->device, 
					cmd, cmd_size, read_buff, read_size);
			}
			else {
				G_SPI_ReceiveBuff((SPI_TypeDef *)device->c_attr->device, 
					read_buff, read_size);
			}
		}
#endif
#if (SPI2_SLAVE_NUMS > 0)
		if (SPI_DEVICE_HSPI == dev_id) {
			spi_master_config_ncs(device, slave, slave_id);
			hspi_master_init_hw(device, slave);
			if (cmd && (cmd_size > 0))
				G_HSPI_SendAndReceiveData((uint8_t *)cmd, cmd_size, read_buff, read_size);
			else
				G_HSPI_ReceiveData(read_buff, read_size);
		}
#endif

		if (timeout > 0)
			retval = gkt_semaphore_acquire(device->semaphore, timeout);
		spi_master_terminate(device);
	}
	else
		retval = GKT_EPARAM;

	return retval;
}

int gkt_spi_master_write_read(gkt_handle_t handle,
			const void *write_data, void *read_buff,
			uint32_t size, uint32_t timeout)
{
	// TODO:
	return GKT_ENOTSUPPORT;
}

GKT_DEVICE_DESC_DEFINE(spi, NORMAL);

